﻿// CLoginDlg.cpp: 实现文件
//

#include "pch.h"
#include "CClient.h"
#include "CLoginDlg.h"
#include "afxdialogex.h"


// CLoginDlg 对话框

IMPLEMENT_DYNAMIC(CLoginDlg, CDialogEx)

CLoginDlg::CLoginDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_LOGIN, pParent)
{

}

CLoginDlg::~CLoginDlg()
{
}

void CLoginDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CLoginDlg, CDialogEx)
	ON_BN_CLICKED(IDC_LOGIN_LOGIN, &CLoginDlg::OnClickedLogin)
	ON_BN_CLICKED(IDC_LOGIN_EXIT, &CLoginDlg::OnClickedExit)
	ON_BN_CLICKED(IDC_SHOW_PWD, &CLoginDlg::OnClickedShowPwd)
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_DESTROY()
	ON_STN_CLICKED(IDC_NOTIFY, &CLoginDlg::OnClickedNotify)
	ON_MESSAGE(UM_PIC_NOTIFY, &CLoginDlg::OnUmPicNotify)
END_MESSAGE_MAP()


// CLoginDlg 消息处理程序


BOOL CLoginDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	HICON hIcon = theApp.LoadIconW(IDI_LOGIN);
	SetIcon(hIcon, FALSE);

	// 设置Picture Control控件到编辑框中
	auto pShow = GetDlgItem(IDC_SHOW);
	if (pShow) {
		CRect rect;
		// 获取窗口在屏幕的位置
		pShow->GetWindowRect(rect);
		CSize size = rect.Size();
		auto pName = GetDlgItem(IDC_LOGIN_NAME);
		pShow->SetParent(pName);
		// 父View设置为编辑框
		// MoveWindow相对于父View
		CRect pRect;
		pName->GetWindowRect(pRect);
		rect = CRect(POINT{pRect.Size().cx - size.cx, 0}, size);
		pShow->MoveWindow(rect, FALSE);
	}

	// 属性中 排序:False
	CComboBox* cb = (CComboBox*)GetDlgItem(IDC_COMBO1);
	cb->SetCurSel(0);

	// 查找窗口
	// :: 全局返回的是 HWND 
	// Cwnd类中 返回的是 CWnd*
	HWND pHnd = ::FindWindow(_T("notepad"), NULL);
	CWnd* cWnd = this->FindWindow(_T("notepad"), NULL);
	if (cWnd) {// 嵌到记事本窗口显示
		// SetParent(pWnd);
		// SetOwner(cWnd); 不起作用

		// CWnd对象 转 HWND句柄
		/*pWnd->m_hWnd;
		pWnd->GetSafeHwnd();
		CWnd cWnd;
		HWND h = cWnd;*/

		// HWND 转 CWnd 一个句柄对应一个对象
		// CWnd::FromHandle(pHnd);

		// 只限函数内使用，变量不适合保存
		//auto n = GetDlgItem(IDC_LOGIN_NAME);
		//CWnd::FromHandle(pHnd);
		//CWnd::DeleteTempMap();// 由于系统会不定时调用该函数清理
	}

	// 实际测试，句柄不变，但对象会变
	CWnd* p_cWnd = GetDlgItem(IDC_LOGIN_NAME);
	CWnd* p_cWnd2 = CWnd::FromHandle(p_cWnd->GetSafeHwnd());
	HWND h1 = p_cWnd->GetSafeHwnd();
	CWnd::DeleteTempMap();
	CWnd* p_cWnd3 = GetDlgItem(IDC_LOGIN_NAME);
	CWnd* p_cWnd4 = CWnd::FromHandle(p_cWnd3->GetSafeHwnd());
	HWND h2 = p_cWnd3->GetSafeHwnd();

	// 不使用CWnd中GetDlgItem获取窗口对象，因为对象会变，参考下面 attach、subclass(2种)、类向导变量
	// 利用Attach绑定对象， 不通过GetDlgItem绑定控件对象
	HWND p_attach = ::GetDlgItem(m_hWnd, IDC_LOGIN_NAME);// 窗口句柄、控件句柄
	p_cWnd5.Attach(p_attach);// 退出时需要手动解除

	// Subclass 包含Attach，再增加消息分发
	// Picture Ctrl 修改属性： 通知-True ，主窗口不能再获取消息
	// 1. 类向导->添加类->MFC类->CPicNotify->CStatic或CWnd派生
	// 2. 类向导->CPicNotify->添加LBUTTONDOWN消息
	// 3. 使用SubclassWindow绑定
	// 4. 使用UnsubclassWindow解绑
	// 5. 绑定升级写法1：p_pic.SubclassDlgItem(IDC_NOTIFY, this); 并且不需要解绑
	// 6. 绑定升级写法2：通过添加变量或类向导添加变量

	HWND p_pic_ = ::GetDlgItem(m_hWnd, IDC_NOTIFY);
	// p_pic.Attach(p_pic_);// 不能转移消息
	p_pic.SubclassWindow(p_pic_);// 可用转移消息
	// p_pic.SubclassDlgItem(IDC_NOTIFY, this);
	p_pic.dlg = this;

	return TRUE;
}


void CLoginDlg::OnClickedLogin()
{
	OnOK();
}


void CLoginDlg::OnClickedExit()
{
	EndDialog(IDCANCEL);
}

// 防止粘包
// 1. 结构体 2. 发送长度 3. 中间回复
void CLoginDlg::OnOK()
{
	EndDialog(IDOK);
}
 
// reinterpret_cast<指针类型>
// static_cast<普通类型>
void CLoginDlg::OnClickedShowPwd()
{
	// 方法一
	//auto pEdit = (CEdit*) GetDlgItem(IDC_LOGIN_PASSWORD);
	//if (pEdit->GetPasswordChar() == 0) {
	//	pEdit->SetPasswordChar(_T('●'));
	//}
	//else {
	//	pEdit->SetPasswordChar(0);
	//}
	//pEdit->RedrawWindow();// 刷新

	// 此方法不好使
	//auto dwStyle = pEdit->GetStyle();
	//if (dwStyle & ES_PASSWORD) {
	//	pEdit->ModifyStyle(ES_PASSWORD, 0);// 左边代表移除的属性，右边代表添加的属性，0就是没有
	//}
	//else {
	//	pEdit->ModifyStyle(0, ES_PASSWORD);// 左边代表移除的属性，右边代表添加的属性，0就是没有
	//}
	
	// 方法二
	auto pEdit = GetDlgItem(IDC_LOGIN_PASSWORD);
	if (!pEdit) {
		return;
	}
	DWORD dwStle = pEdit->GetStyle();
	CString str;
	CRect rect;
	pEdit->GetWindowText(str);
	pEdit->GetWindowRect(rect);
	ScreenToClient(rect);
	CFont* pFont = pEdit->GetFont();
	pEdit->DestroyWindow();// 销毁
	if (dwStle & ES_PASSWORD) {
		pEdit->CreateEx(WS_EX_CLIENTEDGE, _T("EDIT"), str, dwStle & ~ES_PASSWORD, rect, this, IDC_LOGIN_PASSWORD);
	}
	else {
		pEdit->CreateEx(WS_EX_CLIENTEDGE, _T("EDIT"), str, dwStle | ES_PASSWORD, rect, this, IDC_LOGIN_PASSWORD);
	}
	pEdit->SetFont(pFont);

	// 窗口置顶
	if (GetExStyle() & WS_EX_TOPMOST) {
		// SWP_NOMOVE：x,y无效，你随便带入任何数据保持左上角不动，否则左上角根据带入的数据变化。
		// SWP_NOSIZE  ：cx，cy无效，你随便带入任何数据保持高宽不动，否则高宽根据带入的数据变化。
		// SWP_NOZORDER ：第一个参数无效
		SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
	}
	else {
		SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
	}
}

// Picture Control控件 修改 通知： True 对应 -> SS_NOTIFY属性
// 没有通知True，则消息穿透，由主窗口处理
void CLoginDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	// 获取点击位置在矩形范围即可
	CRect rect;
	GetDlgItem(IDC_LOGIN_PIC)->GetWindowRect(rect);
	ScreenToClient(rect);
	if (rect.PtInRect(point)) {
		CEdit* pEdit = reinterpret_cast<CEdit*>(GetDlgItem(IDC_LOGIN_PASSWORD));
		if (pEdit->GetPasswordChar() != 0) {
			pEdit->SetPasswordChar(0);
			pEdit->RedrawWindow();// 窗口重绘
			// 光标锁定 作用是鼠标移走，一样可用获取Up事件
			SetCapture();
		}
	}

	CDialogEx::OnLButtonDown(nFlags, point);
}


void CLoginDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
	// 光标锁定释放
	ReleaseCapture();
	// 获取点击位置在矩形范围即可
	CRect rect;
	GetDlgItem(IDC_LOGIN_PIC)->GetWindowRect(rect);
	ScreenToClient(rect);
	if (rect.PtInRect(point)) {
		CEdit* pEdit = reinterpret_cast<CEdit*>(GetDlgItem(IDC_LOGIN_PASSWORD));
		if (pEdit->GetPasswordChar() == 0) {
			pEdit->SetPasswordChar(_T('●'));
			pEdit->RedrawWindow();// 窗口重绘
		}
	}

	CDialogEx::OnLButtonUp(nFlags, point);
}


void CLoginDlg::OnDestroy()
{
	CDialogEx::OnDestroy();

	p_cWnd5.Detach();// 退出时需要手动解除
	p_pic.UnsubclassWindow();
}


void CLoginDlg::OnClickedNotify()
{
	// 控件合成后的点击消息一样可用接收，但单独的按下抬起需要派生类
	// 打印
	TRACE("-----------------OnClickedNotify\n");
}


afx_msg LRESULT CLoginDlg::OnUmPicNotify(WPARAM wParam, LPARAM lParam)
{
	TRACE("-----------------OnUmPicNotify %d %d\n", wParam, lParam);
	return 0;
}
